package cn.org.timespace.ons.util;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 进制转换工具类
 * @author admin
 *
 */
public class AryUtil {
	private final static Log log = LogFactory.getLog(AryUtil.class);
        private static final Map<Character, Integer> hexDeciamlMap = new HashMap<Character, Integer>();
        
        /*
        * 16进制数字字符集
        */
        private static final String hexString = "0123456789ABCDEF";

        static {
                for(int i=0;i<10;i++) {
                        hexDeciamlMap.put((char)('0' + i), i);
                }
                hexDeciamlMap.put('A', 10);
                hexDeciamlMap.put('B', 11);
                hexDeciamlMap.put('C', 12);
                hexDeciamlMap.put('D', 13);
                hexDeciamlMap.put('E', 14);
                hexDeciamlMap.put('F', 15);
        }

        /**
         * 16进制转换10进制(因为decimalToBinary最大长度32位，所以这里最大长度为4对16进制字符，如EF EF EF FE；最小长度8位，如C4)
         * @param hex 16进制，如C4
         * @return
         */
        public static long hexToDecimal(String hex) {
                hex = hex.toUpperCase();
                StringBuilder binary = new StringBuilder();
                for(char s : hex.toCharArray()) {
                        binary.append(hexToBinary(s));
                }
                return binaryToDecimal(binary.toString());
        }
        
        /**
         * 16进制转换10进制
         * @param hex
         * @return
         */
        public static int hexToInt(String hex) {
        	return Integer.valueOf(hex, 16);
        }


        /**
         * 将10进制转换成16进制
         * @param decimal 最大长度32位
         * @return
         */
        public static String decimalToHex(long num) {
                String binary = decimalToBinary(num);
                StringBuilder hex = new StringBuilder();
                for(int i=0;i<binary.length();i+=4) {
                        String block = binary.substring(i, i+4);
                        hex.append(binaryToHex(block));
                }
                return hex.toString().toUpperCase();
        }

        private static String hexToBinary(char s) {
                StringBuilder binary = new StringBuilder();
                int decimal = hexDeciamlMap.get(s);

                if(decimal - 8 >= 0) {
                        decimal = decimal - 8;
                        binary.append("1");
                }else {
                        binary.append("0");
                }

                if(decimal - 4 >= 0) {
                        decimal = decimal - 4;
                        binary.append("1");
                }else {
                        binary.append("0");
                }

                if(decimal - 2 >= 0) {
                        decimal = decimal - 2;
                        binary.append("1");
                }else {
                        binary.append("0");
                }

                if(decimal - 1 == 0) {
                        decimal = decimal - 1;
                        binary.append("1");
                }else {
                        binary.append("0");
                }
                return binary.toString();
        }

        private static char binaryToHex(String binary) {
                char[] binaryArray = binary.toCharArray();
                int sum = 0;
                if(binaryArray[0] == '1') {
                        sum += 8;
                }
                if(binaryArray[1] == '1') {
                        sum += 4;
                }
                if(binaryArray[2] == '1') {
                        sum += 2;
                }
                if(binaryArray[3] == '1') {
                        sum += 1;
                }

                char hex = 0;
                for(Map.Entry<Character, Integer> entry : hexDeciamlMap.entrySet()) {
                        if(entry.getValue() == sum) {
                                hex = entry.getKey();
                        }
                }
                return hex;
        }

        /**
         * 10进制转2进制(最大长度32位)
         * @return
         */
        public static String decimalToBinary(long num) {
                char[] binary = Long.toBinaryString(Math.abs(num)).toCharArray();
                int length = ((binary.length / 4) + 1) * 4;
                if(length < 8) {
                        length = 8;
                }

                char[] result = new char[length];
                int pos = result.length - 1;
                for(int i=binary.length-1;i>=0;i--,pos--) {
                        result[pos] = binary[i];
                }
                for(int i=0;i<result.length;i++) {
                        if(result[i] == 0) {
                                result[i] = '0';
                        }
                }
                if(num < 0) {
                        //取反、加1
                        String b = reverse(new String(result));
                        b = binaryOperate(b, 1);
                        result = b.toCharArray();
                }
                return new String(result);
        }

        /**
         * 2进制(32位)转10进制
         * @return
         */
        public static long binaryToDecimal(String binary) {
                if(binary.startsWith("1")) {
                        //减1、取反、加负号
                        binary = binaryOperate(binary, -1);
                        binary = reverse(binary);
                        //Integer.parseInt("10000000000000000000000000000000", 2) 会出错，所以用Long.parseLong()
                        return -1 * Long.parseLong(binary, 2);
                }else {
                        return Long.parseLong(binary, 2);
                }
        }


        /**
         * 取二进制的反码
         * @param binary
         * @return
         */
        private static String reverse(String binary) {
                char[] array = binary.toCharArray();
                for(int i=0;i<array.length;i++) {
                        if(array[i] == '0') {
                                array[i] = '1';
                        }else {
                                array[i] = '0';
                        }
                }
                return new String(array);
        }

        /**
         * 二进制加减运算<br/>
         * 例如：<br/>
         * String s = "10000000"; <br/>
         * System.out.println(binaryOperate(s.toCharArray(), -1));  //结果01111111 <br/>
         * System.out.println(binaryOperate(s.toCharArray(), 1));   //结果10000001 <br/>
         * System.out.println(binaryOperate(s.toCharArray(), 2));   //结果10000010 <br/>
         *
         * @param binary
         * @param num 要加减的十进制数位数
         * @return
         */
        private static String binaryOperate(String binary, int num) {
                char[] array = binary.toCharArray();
                boolean plus = true;
                if(num < 0) {
                        plus = false;
                }
                for(int i=0;i<Math.abs(num);i++) {
                        binaryCarry(array, array.length -1, plus);
                }
                return new String(array);
        }

        /**
         * 二进制加减运算工具类
         * @param array
         * @param pos
         * @param plus
         * @return
         */
        private static boolean binaryCarry(char[] array, int pos, boolean plus) {
                if(pos < 0 || pos >= array.length) {
                        return false;
                }
                char oldChar = '0';
                char newChar = '1';
                if(!plus) {
                        oldChar = '1';
                        newChar = '0';
                }
                if(array[pos] == oldChar) {  //不需要借位
                        array[pos] = newChar;
                }else {
                        if(binaryCarry(array, pos - 1, plus)) { //需要向上一位借位
                                array[pos] = oldChar;
                        }else {
                                return false;  //借位失败，说明已达最大值
                        }
                }
                return true;
        }
        
        /**
    	 * 字符串转换成十六进制字符串
    	 */
    	public static String str2HexStr(String str) {

    		char[] chars = "0123456789ABCDEF".toCharArray();
    		StringBuilder sb = new StringBuilder("");
    		byte[] bs = str.getBytes();
    		int bit;
    		for (int i = 0; i < bs.length; i++) {
    			bit = (bs[i] & 0x0f0) >> 4;
    			sb.append(chars[bit]);
    			bit = bs[i] & 0x0f;
    			sb.append(chars[bit]);
    		}
    		return sb.toString();
    	}

    	/**
    	 * 
    	 * 十六进制转换字符串
    	 */
    	public static String hexStr2Str(String hexStr) {
    		return new String(hexStr2byte(hexStr));
    	}
    	
    	/**
    	 * 
    	 * 十六进制转换字符串
    	 */
    	public static byte[] hexStr2byte(String hexStr) {
    		String str = "0123456789ABCDEF";
    		char[] hexs = hexStr.toCharArray();
    		byte[] bytes = new byte[hexStr.length() / 2];
    		int n;
    		for (int i = 0; i < bytes.length; i++) {
    			n = str.indexOf(hexs[2 * i]) * 16;
    			n += str.indexOf(hexs[2 * i + 1]);
    			bytes[i] = (byte) (n & 0xff);
    		}
    		return bytes;
    	}

    	/**
    	 * bytes转换成十六进制字符串
    	 */
    	public static String byte2HexStr(byte[] b) {
    		String hs = "";
    		String stmp = "";
    		for (int n = 0; n < b.length; n++) {
    			stmp = (Integer.toHexString(b[n] & 0XFF));
    			if (stmp.length() == 1)
    				hs = hs + "0" + stmp;
    			else
    				hs = hs + stmp;
    		}
    		return hs.toUpperCase();
    	}
    	
    	/**
    	 * 十六进制数相加操作
    	 * @param hex1
    	 * @param hex2
    	 * @return
    	 */
    	public static String hexAdd(String hex1, String hex2) {
    		long x = Long.parseLong(hex1, 16); 
    		long y = Long.parseLong(hex2, 16); 
    		
    		String addHex = Long.toHexString(x+y);
    		
    		return addHex;
    	}
    	
    	/**
    	 * 字符串中每个字符先转成十六进制，再相加得到十六进制和
    	 * @param array
    	 * @return
    	 */
    	public static String string2HexAdd(String array) {
    		String addHex = null;
        	String hex = null;
        	for(int j = 0; j < array.length(); j++) {
        		hex = AryUtil.str2HexStr(String.valueOf(array.charAt(j)));
        		if(j == 0)
        			addHex = hex;
        		else
        			addHex = hexAdd(addHex, hex);
        	}
        	
        	return addHex;
    	}
    	
    	/*
    	* 将字符串编码成16进制数字,适用于所有字符（包括中文）
    	*/
    	public static String stringToHex(String str) {
    		// 根据默认编码获取字节数组
    		byte[] bytes = str.getBytes();
    		StringBuilder sb = new StringBuilder(bytes.length * 2);
    		// 将字节数组中每个字节拆解成2位16进制整数
    		for (int i = 0; i < bytes.length; i++) {
	    	    sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4));
	    	    sb.append(hexString.charAt((bytes[i] & 0x0f) >> 0));
    		}
    		return sb.toString();
    	}

    	/*
    	* 将16进制数字解码成字符串,适用于所有字符（包括中文）
    	*/
    	public static String hexToString(String bytes) {
    		ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length() / 2);
    		// 将每2位16进制整数组装成一个字节
    		for (int i = 0; i < bytes.length(); i += 2)
    			baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString.indexOf(bytes.charAt(i + 1))));
    		
    	   return new String(baos.toByteArray());
    	}
    	
    	public static String toStringHex(String s) {
    		byte[] baKeyword = new byte[s.length() / 2];
    		for (int i = 0; i < baKeyword.length; i++) {
    			try {
    				baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(
    						i * 2, i * 2 + 2), 16));
    			} catch (Exception e) {
    				log.error(e);
    				e.printStackTrace();
    			}
    		}

    		try {
    			s = new String(baKeyword, "utf-8");// UTF-16le:Not
    		} catch (Exception e1) {
    			e1.printStackTrace();
    		}
    		return s;
    	}
    	
        public static void main(String[] args) throws UnsupportedEncodingException {
        	String hex = "000AFCD9";
        	System.out.println(AryUtil.toStringHex(hex));
        }
}

